package model.cliente;

import java.util.HashSet;
import java.util.Set;

import excepciones.cliente.ClienteNoEsAptoParaPrestamoException;
import excepciones.prestamos.CantidadDeCuotasInvalidaException;
import excepciones.prestamos.MontoInvalidoDePrestamoException;
import model.prestamos.Prestamo;
import model.prestamos.seguroDeVida.TipoDeSeguroDeVida;
import model.sistema.Sistema;


/**
 * Esta clase representa a los clientes dentro del banco y 
 * determina sus capacidades y responsabilidades
 * @author Emanuel
 */
public abstract class Cliente {

	protected Set<Prestamo> prestamos;
	protected Sistema banco;
	
	public Cliente(Sistema banco){
		this.prestamos=new HashSet<Prestamo>();
		this.banco=banco;
		banco.guardarCliente(this);
	}

	public Set<Prestamo> getPrestamos() {
		return prestamos;
	}
	
	/**
	 * Metodo para solicitar nuevos prestamos a un banco
	 * @param monto el monto del prestamo
	 * @param cantCuotas la cantidad de cuotas para el prestamos
	 * @param tipoSeguroDeVida el tipo de seguro de vida elegido para el prestamo
	 * 
	 * @throws CantidadDeCuotasInvalidaException cuando la cantidad de cuotas es negativa o nula
	 * @throws MontoInvalidoDePrestamoException cuando el monto es negativo o nulo
	 * @throws ClienteNoEsAptoParaPrestamoException cuando el cliente no es apto para recibir prestamos
	 */
	public void solicitarPrestamo(double monto, int cantCuotas, TipoDeSeguroDeVida tipoSeguroDeVida) 
			throws CantidadDeCuotasInvalidaException, MontoInvalidoDePrestamoException, ClienteNoEsAptoParaPrestamoException{
		if(this.aptoParaPrestamo()){
			this.banco.nuevoPrestamoPara(this,monto,cantCuotas,tipoSeguroDeVida);
		}else{
			throw new ClienteNoEsAptoParaPrestamoException();
		}
	}
	
	public int cantPrestamosActivos(){
		int totalActivos=0;
		for(Prestamo prestamo: this.prestamos){
			if(prestamo.esActivo()){
				totalActivos+=1;
			}
		}
		return totalActivos;
	}
	
	public boolean tienePrestamoEnDeuda() {
		for(Prestamo prestamo: this.prestamos){
			if(prestamo.esEnDeuda()){
				return true;
			}
		}
		return false;
	}

	public boolean tienePrestamoSolicitado() {
		for(Prestamo prestamo: this.prestamos){
			if(prestamo.esSolicitado()){
				return true;
			}
		}
		return false;
	}
		
	public abstract void agregarPrestamo(Prestamo prestamo);
	
	public abstract boolean aptoParaPrestamo();
	
	public abstract void notificarNuevaCuotaDe(Prestamo prestamo);
	
	public abstract boolean nombreClienteComienzaCon(String criterio);

	public abstract boolean clienteTieneDNI(int criterio);
	
	public abstract void updateTipo();
	
	public abstract void yaNoEsAptoPorIncobrable();
	
	public abstract boolean contieneACliente(Cliente cliente);
	
}



